using System;
using System.Collections.Generic;
using System.Text;
using LispInterpretor.InBuiltProcedures;
using LispInterpretor.InBuiltProcedures.LogicalOperators;
using LispInterpretor.InBuiltProcedures.ListOperations;
using LispInterpretor.HelperClasses;

namespace LispInterpretor
{
    public class Environment
    {
        private Environment parentEnvironment;

        public Environment Parent
        {
            get
            {
                return parentEnvironment;
            }
        }

        public Environment(Environment environment)
        {
            parentEnvironment = environment;
        }

        Dictionary<string, object> environment = new Dictionary<string, object>();
        
        public Environment()
        {
            environment.Add("+", new Add());
            environment.Add("-", new Subtract());
            environment.Add("*", new Multiply());
            environment.Add("/", new Divide());
            environment.Add("=", new Equals());
            environment.Add("and", new And());
            environment.Add("or", new Or());
            environment.Add("not", new Not());
            environment.Add("first", new First());
            environment.Add("rest", new Rest());
            environment.Add("concat", new Concat());
        }

        public bool Exists(string key)
        {
            if (environment.ContainsKey(key))
            {
                return true;
            }

            if (parentEnvironment != null)
            {
                return parentEnvironment.Exists(key);
            }

            return false;
        }

        public object Get(string key)
        {
            if (environment.ContainsKey(key))
            {
                return environment[key];
            }

            if (parentEnvironment != null)
            {
                return parentEnvironment.Get(key);
            }

            throw new InvalidProgramException("Undeclared variable use.");
        }

        public void Add(string key, object value)
        {
            Check.IsTrue(!environment.ContainsKey(key), string.Format("The label, {0}, is already bound.", key));
            environment.Add(key, value);
        }
    }
}
